import time
from flask import Flask, send_file, request, Response, jsonify
from gevent import pywsgi
from pptx import Presentation
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.util import Inches
from pptx.enum.chart import XL_DATA_LABEL_POSITION
from pptx.enum.chart import XL_LEGEND_POSITION
from pptx.util import Pt
from pptx.util import Cm  # Inches
import os
import shutil
import json
import uuid

from flask_apscheduler import APScheduler
app = Flask(__name__)

# ppt临时文件存放文件夹
PPT_DIR_NAME = 'tmpDir'

# 支持的组件
modules = {
    "COLUMN_CLUSTERED": XL_CHART_TYPE.COLUMN_CLUSTERED,
    "LINE": XL_CHART_TYPE.LINE,
    "PIE": XL_CHART_TYPE.PIE,
    "DOUGHNUT": XL_CHART_TYPE.DOUGHNUT,
    "RADAR": XL_CHART_TYPE.RADAR,
    "TABLE": None
}

aps = APScheduler()
# 定时器配置
class Config(object):
    JOBS = [
        {
            'id': 'job1',
            'func': 'web-ppt-export:task',
            'trigger': 'cron',
            'day': '*',
            'hour': '01',
            'minute': '59',
            'second': '59'
        }
    ]
    SCHEDULER_API_ENABLED = True

def task():
    print('execute task')
    shutil.rmtree(PPT_DIR_NAME)


@app.route('/')
def hello_world():
   return 'Hello World'


def file_send(file_path):  # 发送大文件可以该方法
   with open(file_path, 'rb') as f:
      while 1:
         data = f.read(20 * 1024 * 1024)  # 每次读取20M
         if not data:
            break
         yield data

@app.route("/ppt/export",methods=['POST'])
def download():
    data = request.get_data(as_text=True)
    jsonArr = json.loads(data)
    print(jsonArr)
    # create presentation with slides ------
    prs = Presentation()
    for jsonObj in jsonArr:
        if jsonObj["chartType"] == "TABLE":
            createTable(prs, jsonObj)
        else:
            createChart(prs, jsonObj)
    if not os.path.exists(PPT_DIR_NAME):
        os.mkdir(PPT_DIR_NAME)
    fileName = PPT_DIR_NAME + '/%d.pptx' % int(time.time())
    prs.save(fileName)
    response = Response(file_send(fileName), content_type='application/octet-stream')
    response.headers["Content-disposition"] = f'attachment; filename={fileName}'
    return response

@app.route('/json',methods=['POST'])
def json_body():
    data = request.get_data(as_text=True)
    print(data)
    jsonObj = json.loads(data)
    print(jsonObj[0]['categories'][0])
    return jsonify(jsonObj)

# 创建图表slide
def createChart(prs, params):

    slide = prs.slides.add_slide(prs.slide_layouts[6])

    # define chart data ---------------------
    chart_data = ChartData()
    chart_data.categories = params["categories"]
    # add series data
    for key in params["series"].keys():
        print(key)
        chart_data.add_series(key, tuple(params["series"][key]))

    # add chart to slide --------------------
    x, y, cx, cy = Inches(0.5), Inches(0.5), Inches(8.5), Inches(6.5)
    chart = slide.shapes.add_chart(
        modules[params["chartType"]], x, y, cx, cy, chart_data).chart

    chart.font.size = Pt(10)
    chart.has_legend = True
    chart.legend.position = XL_LEGEND_POSITION.BOTTOM

    chart.plots[0].has_data_labels = True
    data_labels = chart.plots[0].data_labels
    if "numberFormat" in params and params["numberFormat"] == "%0":
        data_labels.number_format = '0%'
    data_labels.position = XL_DATA_LABEL_POSITION.ABOVE

    chart.has_title = True
    chart.chart_title.text_frame.clear()  # 清除原标题
    new_paragraph = chart.chart_title.text_frame.add_paragraph()  # 添加一行新标题
    new_paragraph.text = params["title"]  # 新标题
    new_paragraph.font.size = Pt(15)  # 新标题字体大小

    chart.has_legend = True
    chart.legend.position = XL_LEGEND_POSITION.TOP
    chart.legend.include_in_layout = False

# 创建表格slide
def createTable(prs, params):
    title_only_slide_layout = prs.slide_layouts[5]
    slide = prs.slides.add_slide(title_only_slide_layout)
    shapes = slide.shapes

    shapes.title.text = params["title"]

    # 定义表格数据 ------
    name_objects = params["categories"]

    # 表格样式 --------------------
    rows = len(params["series"])
    cols = len(params["series"][0])
    top = Cm(4.0)
    left = Cm(0.5)  # Inches(2.0)
    width = Cm(24)  # Inches(6.0)
    height = Cm(14)  # Inches(0.8)

    # 添加表格到幻灯片 --------------------
    table = shapes.add_table(rows, cols, left, top, width, height).table

    for i in range(cols):
        # 设置单元格宽度
        table.columns[i].width = Cm(int(24/cols))

    # 填充数据
    for i in range(0, rows):
        for j in range(cols):
            if i == 0:
                # 设置标题行
                table.cell(0, j).text = name_objects[j]
            else:
                table.cell(i, j).text = str(params["series"][i][j])

            # 设置单元格字体大小
            cellFont = int(160 / rows)
            if cellFont < 5:
                cellFont = 5
            if cellFont > 14:
                cellFont = 14
            print(cellFont)
            table.cell(i, j).text_frame.paragraphs[0].font.size = Pt(cellFont)

if __name__ == '__main__':
    app.config.from_object(Config())

    scheduler = APScheduler()
    scheduler.init_app(app)
    scheduler.start()

    server = pywsgi.WSGIServer(('0.0.0.0', 33689), app)
    server.serve_forever()